package com.sibco.client.common.mail;

import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.mail.internet.InternetAddress;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.apache.commons.lang.StringUtils;
import org.apache.xerces.dom.DeferredCDATASectionImpl;
import org.w3c.dom.Document;
import org.w3c.dom.Node;

import com.bstek.dorado.common.UserConfig;
import com.sibco.client.common.Tools;
import com.sibco.client.common.XMLUtil;


@SuppressWarnings("unchecked")
public class MailService {
	private static final String IDENTIFIER = "#";
	private boolean onOff;
	private String serverAddress;
	private String mailFrom;
	private String mailFromName;
	private String mailer;
	private String MailerName;
	private String MailerPwd;
	private String charset;
	private String encode_type;
	private String contentType;
	private boolean NeedAuth;
	
	public Map templateMap = new HashMap();
	
	private static MailService mailService;
	public static synchronized MailService getInstance() throws Exception {
		if (mailService==null) {
			return new MailService();
		}else
			return mailService;
    }
	private MailService() throws Exception{
		init("/MailConfig/MailConfig.xml");
	}
	
	private boolean init(String configFile) throws Exception {
		Node config = null;
		DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
		Document configRoot = null;
		DocumentBuilder builder = factory.newDocumentBuilder();
		
		//File f = new File(this.getClass().getResource("/").getPath());
		//File f = new File(getServletConfig().getServletContext().getRealPath("/"));
		//configFile = f.getPath() + configFile;
		
		configFile=UserConfig.getString("public_path")+configFile;
		File f = new File(configFile);
			
		configRoot = builder.parse(f);
		config = configRoot.getDocumentElement();
		if (config == null
				|| "SendEmailConifg".compareToIgnoreCase(config.getNodeName()) != 0) {
			return false;
		}
		Node child = XMLUtil.getNextChildElement(config);
		if (child == null
				|| "Switch".compareToIgnoreCase(child.getNodeName()) != 0) {
			return false;
		}
		this.onOff = "on".equalsIgnoreCase(XMLUtil.getNodeTextValue(child));

		child = XMLUtil.getNextSiblingElement(child);
		
		if (child == null
				|| "NeedAuth".compareToIgnoreCase(child.getNodeName()) != 0) {
			return false;
		}
		this.NeedAuth = "yes".equalsIgnoreCase(XMLUtil.getNodeTextValue(child));

		child = XMLUtil.getNextSiblingElement(child);
		
		if (child == null
				|| "ServerAddress".compareToIgnoreCase(child.getNodeName()) != 0) {
			return false;
		}
		this.serverAddress = XMLUtil.getNodeTextValue(child);

		child = XMLUtil.getNextSiblingElement(child);
		if (child == null
				|| "Charset".compareToIgnoreCase(child.getNodeName()) != 0) {
			return false;
		}
		this.charset = XMLUtil.getNodeTextValue(child);

		child = XMLUtil.getNextSiblingElement(child);
		if (child == null
				|| "Encode".compareToIgnoreCase(child.getNodeName()) != 0) {
			return false;
		}
		this.encode_type = XMLUtil.getNodeTextValue(child);

		child = XMLUtil.getNextSiblingElement(child);
		if (child == null
				|| "ContentType".compareToIgnoreCase(child.getNodeName()) != 0) {
			return false;
		}
		this.contentType = XMLUtil.getNodeTextValue(child);

		child = XMLUtil.getNextSiblingElement(child);
		if (child == null
				|| "MailFrom".compareToIgnoreCase(child.getNodeName()) != 0) {
			return false;
		}
		this.mailFrom = XMLUtil.getNodeTextValue(child);

		child = XMLUtil.getNextSiblingElement(child);
		if (child == null
				|| "MailFromName".compareToIgnoreCase(child.getNodeName()) != 0) {
			return false;
		}
		this.mailFromName = XMLUtil.getNodeTextValue(child);

		child = XMLUtil.getNextSiblingElement(child);
		if (child == null
				|| "Mailer".compareToIgnoreCase(child.getNodeName()) != 0) {
			return false;
		}
		this.mailer = XMLUtil.getNodeTextValue(child);

		child = XMLUtil.getNextSiblingElement(child);
		if (child != null && "Templates".equals(child.getNodeName())) {
			Node templateChild = XMLUtil.getNextChildElement(child);
			while (templateChild != null) {
				if ("Template".equals(templateChild.getNodeName())) {
					String templateFile = XMLUtil
							.getNodeTextValue(templateChild);
					System.out.println("0000000000000000000000000000000000000:"+configFile);
					System.out.println("1111111111111111111111111111111111111:"+new File(configFile).getParent());
					System.out.println("2222222222222222222222222222222222222:"+new File(configFile).getParent()+"/"+templateFile);
					
					MailTemplate template = parseTemplate(new File(new File(configFile).getParent()+"/"+templateFile));
					
					
					if (template != null) {
						templateMap.put(template.getType(), template);
					}
					templateChild = XMLUtil.getNextSiblingElement(templateChild);
				}
			}
		}

		child = XMLUtil.getNextSiblingElement(child);
		if (child == null
				|| "MailerName".compareToIgnoreCase(child.getNodeName()) != 0) {
			return false;
		}
		this.MailerName = XMLUtil.getNodeTextValue(child);

		child = XMLUtil.getNextSiblingElement(child);
		if (child == null
				|| "MailerPwd".compareToIgnoreCase(child.getNodeName()) != 0) {
			return false;
		}
		this.MailerPwd = XMLUtil.getNodeTextValue(child);
		return true;
	}
	
	private Node getNextChildCDATAElement(Node node) {
		Node childNode = node.getFirstChild();
		while (null != childNode) {
			if (childNode.getNodeType() == Node.CDATA_SECTION_NODE) {
				return childNode;
			}
			childNode = childNode.getNextSibling();
		}
		return null;
	}
	
	private MailTemplate parseTemplate(File configFile) {
		MailTemplate template = null;
		try {
			Node config = null;
			DocumentBuilderFactory factory = DocumentBuilderFactory
					.newInstance();
			Document configRoot = null;
			DocumentBuilder builder = factory.newDocumentBuilder();
			configRoot = builder.parse(configFile);
			config = configRoot.getDocumentElement();
			if (config == null
					|| "MailTemplate".compareToIgnoreCase(config.getNodeName()) != 0) {
				//logger.error("parseTemplate error,<MailTemplate> node not found");
				return null;
			}
			String type = XMLUtil.getNodeAttributeValue(config, "type");

			Node child = XMLUtil.getNextChildElement(config);
			if (child == null
					|| "subject".compareToIgnoreCase(child.getNodeName()) != 0) {
				//logger.error("parseTemplate error,<subject> node not found");
				return null;
			}
			String subject = XMLUtil.getNodeTextValue(child);
			child = XMLUtil.getNextSiblingElement(child);
			if (child == null
					|| "content".compareToIgnoreCase(child.getNodeName()) != 0) {
				//logger.error("parseTemplate error,<content> node not found");
				return null;
			}
			DeferredCDATASectionImpl dataChild = (DeferredCDATASectionImpl) getNextChildCDATAElement(child);
			if (dataChild == null) {
				//logger.error("parseTemplate error,<cdata> node not found");
				return null;
			}
			String content = dataChild.getData();
			template = new MailTemplate();
			template.setType(type);
			template.setSubject(subject);
			template.setContent(content);
		} catch (Exception e) {
			e.printStackTrace();
			//logger.error("parseTemplate error,", e);
			return null;
		}
		return template;
	}
	
	public String getConvertedString(String str, Map param) {
		if (param == null) {
			return str;
		}
		Iterator it = param.keySet().iterator();
		String resultStr = str;
		while (it.hasNext()) {
			String key = (String) it.next();
			resultStr = StringUtils.replace(resultStr, IDENTIFIER + key + IDENTIFIER, (String) param.get(key));
		}
		return resultStr;
	}

	public void sendMail(MailBean mailBean, String subject,
			String content) throws Exception {
		if(!onOff){
			return;
		}
		SendMail smail = new SendMail();
		smail.setHost(serverAddress);
		smail.setFrom(mailFrom);
		smail.setFromName(mailFromName);
		smail.setMailer(mailer);
		smail.setTo(mailBean.getMailTo());
		smail.setSubject(subject);
		smail.setCharset(charset);
		smail.setEnc(encode_type);
		smail.setFiles(mailBean.getFiles());
		if ("text/html".equalsIgnoreCase(contentType)) {
			smail.setContentType(SendMail.CONTENTTYPE_BOTH);
		} else if ("text".equalsIgnoreCase(contentType)) {
			smail.setContentType(SendMail.CONTENTTYPE_TEXT);
		} else if ("html".equalsIgnoreCase(contentType)) {
			smail.setContentType(SendMail.CONTENTTYPE_HTML);
		}
		if (mailBean.getRecipientCCs() != null && mailBean.getRecipientCCs().length != 0) {
			List ccList = new ArrayList();
			for (int i = 0; i < mailBean.getRecipientCCs().length; i++) {
				ccList.add(new InternetAddress(mailBean.getRecipientCCs()[i]));
			}
			smail.setRecipient((InternetAddress[]) ccList
					.toArray(new InternetAddress[0]));
		}
		smail.setText(content);
		if(NeedAuth)
			smail.sendByAuth(MailerName, MailerPwd);
		else
			smail.send();
	}

	public void sendMail(MailBean bean) throws Exception {
		if(!onOff){
			return;
		}
		if (bean == null) {
			//logger.error("sendMail failed,MailBean is null.");
			return;
		}
		if (bean.getTemplateType() == null
				|| bean.getTemplateType().length() == 0) {
			sendMail(bean, bean
					.getSubject(), bean.getContent());
		} else {
			MailTemplate template = (MailTemplate) templateMap.get(bean
					.getTemplateType());
			if (template == null) {
				//logger.error("sendMail failed,MailTemplate is null.");
				return;
			}
			Map param = bean.getSubjectParamMap();
			String subject = "";
			if("".equals(Tools.toStr(bean.getSubject())))
				subject = bean.getSubject();
			else{
				subject = template.getSubject();
			}
			subject = getConvertedString(subject, param);
			String content = template.getContent();
			param = bean.getContentParamMap();
			content = getConvertedString(content, param);
			sendMail(bean, subject, content);
		}
	}
	
	public static void main(String[] args) throws Exception {
		
	}
}
